﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<iostream>
using namespace std;
c语言struct只有变量
c++语言struct 既有变量，也有函数
抽象事物：抽象事物的特征
类：抽象事物的特征的规则
规则（类）     藏獒
犬种             2
犬龄            150
体重           黑白花色
花色            大脑袋
4.1.2 类的封装·
类：就是一个复合的数据类型（例如：struct）即包含表达属性的成员变量，也包含表达行为的成员函数
类可用于表达那些不能直接与内置基本类型建立自然映射关系的逻辑抽象
类是现实世界的抽象，对象是类在虚拟世界的实例

封装：
1：将属性和行为作为一个整体，表现生活的事物
2：将属性和行为加以权限控制
定义XXX   给变量分内存
访问权限：
Public  公有成员 谁都可以访问       外部，内部  子类
Protected 保护成员  只有自己和子类可以访问
Private    私有成员   只有自己可以访问
Struct  默认为公有
Class    默认为私有
编译器编译类的时候，先编译类中的成员变量，然后编译类中的函数
例子：
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<iostream>
using namespace std;

class human
{
public:
	void set(int age = 0, const char* name = "无名")//桥梁函数
	{
		if (!strcmp(name, "小二"))
		{
			return;
		}
		m_age = age;
		strcpy(m_name, name);
	}
	void get()
	{
		cout << "姓名" << m_name << "年龄" << m_age << endl;
	}
public:
	int m_age;
	char m_name[256];
};

//以上代码模拟类的设计者（例如：类库，被人设计的类，自己设计的类）

//以下代码模拟用户（使用类的人）
int main()
{
	human h;//定义h（给h分配内存空间）在h所占的内存空间中，定义 m_age,m_name  初值为随机值
	h.set(10, "张飞");
	h.get();
}

成员函数参数--this
一个程序有两个对象（h, h2），每个对象中各有一份成员变量（一共两份），成员函数共享一份
对象h内没有存储函数，函数存储在代码端
栈区：局部变量  函数参数和返回值
堆区：动态内存分配
BSS : 为初始化的全局变量  静态变量
数据区：初始化的全局变量  静态变量
代码区：函数  main()   函数只存一份
This 指针   除了静态成员函数以外，类的每个成员函数都有一个隐藏的指针型参数，参数名为this  指向调用该成员函数的对象，这就是this指针，对所有成员的访问，都是通过this指针访问
在函数参数中补上静态参数  类  human 	void set(编译器补上human* this, int age = 0, const char* name = "无名")                     h.set(&h, 20, ”张飞”)
1：那个对象调用成员函数  那么成员函数的this参数就指向哪个对 * *****************
2：在类的成员函数中（除了静态成员函数外），对所有成员的访问都是通this指针进行的   通过给函数中的成员前补充this   this->m_name
3：必须自己明显写  this的情况
1.有时为了方便，将类的成员变量和该类成员函数的参数取相同标识符，这是在成员函数内部，可以通过this指针将二者加以区分
class Integer
{
public:
	void setinfo(/*Integer* this */int i)
	{
		this->i = i;//必须要写this
	}
	Int i;
	2.返回基于this的自引用，以支持串连调用
		Integer & increment(/*Integer* this */)
	{
		++i;
		return *this;//返回基于this指针的自引用
	}
private:
	int i;
};
int main()
{
	Integer AI;
	AI.increment();//返回值this指向AI即this为AI的地址  *this为AI本身   该函数的意义为给AI.ncrement()为AI的别名
	//因此可以串连调用
	AI.increment().increment().increment();
	cout << i << endl;//i=1003  调用三次 i自加3次
	3.将this作为函数的参数，以实现对象交互
		类
	{
		print(this);//3.将this作为函数的参数，以实现对象交互
	};
	//全局函数
	void print(Integer* V)
	{
		//实现
	}

	常对象  ：被const关键词修饰的对象，对象指针或对象引用，统称常对象
		Const int   const int* const int&
		常函数 ：在类成员函数的形参表之后，函数体之前加上 / const关键字，该成员函数的this指针即具有常属性，这样的成员函数称为常函数
		两个完全相同的函数一个加const可以构成重载函数
		常函数内不能修改成员变量
class human
{
public:
	void set(int age = 0, const char* name="无名")//桥梁函数
	{
		if (!strcmp(name,"小二"))
		{
			return;
		}
		m_age = age;
		strcpy(m_name , name);
	}
	void get()
	{
		cout << "姓名" << m_name << "年龄" << m_age << endl;
	}
public:
	int m_age;
	char m_name[256];
};

//以上代码模拟类的设计者（例如：类库，被人设计的类，自己设计的类）

//以下代码模拟用户（使用类的人）


class Integer
{
public:
	void setinfo(/*Integer* this */int i)
	{
		this->i = i;//1.必须要写this
	}
	void getinfo(/*Integer* this */)
	{
		cout << /*this->*/i << endl;
	}
	Integer& increment(/*Integer* this */)
	{
		++i;
		return *this;//2.返回基于this指针的自引用
	}
	int i;
	print(this);//3.将this作为函数的参数，以实现对象交互
};

//全局函数
void print(Integer* V)
{
	//实现
}
int main()
{
	Integer AI;
	AI.increment();//返回值this指向AI即this为AI的地址  *this为AI本身   该函数的意义为给AI.ncrement()为AI的别名
	//因此可以串连调用
	AI.increment().increment().increment();
	cout <<AI.i << endl;//i=1003  调用三次 i自加3次
}
常对象和常函数
class Integer
{
public:
	void setinfo(/*Integer* this */int i)
	{
		m_i = i;//1.必须要写this
	}
	void getinfo(/* const Integer* this */) const  //常函数
	{
		//修改m_i   方法2：const_cast<Integer*>(this)->m_i=8888;
		m_i = 8888;//不能修改  原因：const Integer*为常指针  常指针指向的对象不能修改  类的成员变量不能修改
		cout << "常函数" << endl;
	}
	void getinfo(/* Integer* this */) //非常函数
	{
		cout << "非常函数" << endl;
	}
	//两函数为重载函数
	int m_i;
	//方法1：mutable int m_i;
	//用 1.mutable修饰就可以修改   mutable int m_i;  2.强制类型转化  const_cast<Integer*>(this)
}
int main()
{
	Integer ix;
	ix.setinfo(100); 
	ix.getinfo();//ix.getinfo(&ix);->实参类型为 Integer*  非常对象优先选择非常函数，也可以选择常函数、
	const Integer cix = ix;
	cix.getinfo();//getinfo(&ix)->实参类型为const Integer*  常函数优先选择常函数,不会选择非常函数
}

**********************************************************************************************************
类的定义和实例化
1：构造函数：
函数名与类名相同，且没有返回值类型
class human
{
public:
	human(int age,char name[20])
	{
		cou << "human类的构造函数" << endl;
	}//***************构造函数
	void set(int age = 0, const char* name = "无名")//桥梁函数
	{
		if (!strcmp(name, "小二"))
		{
			return;
		}
		m_age = age;
		strcpy(m_name, name);
	}
	void get()
	{
		cout << "姓名" << m_name << "年龄" << m_age << endl;
	}
public:
	int m_age;
	char m_name[256];
};
2：构造函数调用时间
在定义对象同时自动被调用，且仅被调用一次
对象定义语句  栈区 human h;//定义h(给h分配内存空间)，调用h.human()函数
	new操作符  堆空间
3：构造函数的作用
   定义对象的各个成员变量并赋初值。设置对象的初始状态  对象的状态由对象的每个变量决定
		class human
	{
	public:
		human(/* human* this  //定义的对象h */int age=0, char name[20]="无名")
		{
			//在this所指向的内存空间中，定义m_age，初值为随机数
			//在this所指向的内存空间中，定义m_name[256]，初值为随机数
			cou << "human类的构造函数" << endl;
			strcpy(this->m_name, name);
			m_age = age;
		}
		void getinfo(/*Integer* this */);//声明
	public:
		int m_age;//声明
		char m_name[256];//声明
	};
	void human::getinfo(/*Integer* this */)
	{
		cout << /*this->*/i << endl;
	}
	human h(22, "张飞");//==定义h(给h分配内存空间)，调用h.human(22,"张飞")函数
	int main()
	{

	}
	在对象定义之初想实现的任何操作
*******************************************************************************************************
		类的声明和定义可以分开
		函数的分离
	class 类名
	{
		返回类型 函数名(形参表);声明
	};
	返回类型  类名::函数名(形参表)
	{
		函数体;
	};

	构造函数的分离
		好处：多文件开发
		声明放于.h文件中
		定义放于.cpp文件中
	class human
	{
	public:
		human(/* human* this  //定义的对象h */int age = 0, char name[20] = "无名");//声明
	public:
		int m_age;//声明
		char m_name[256];//声明
	};
	human::human(/* human* this  //定义的对象h */int age, char name[20])
	{
		//在this所指向的内存空间中，定义m_age，初值为随机数
		//在this所指向的内存空间中，定义m_name[256]，初值为随机数
		cou << "human类的构造函数" << endl;
		strcpy(this->m_name, name);
		m_age = age;
	}
	*****************************************************************************************
实例化
定义类对象的1种方法
1.在栈中定义单个对象
	类名 对象；//不要加空格
	human h2;//定义h2,调用h2.human()
	类名 对象(实参表)
		human h2(20, "张三");
		2.在栈中定义对象数组
		类名 对象数组[元素个数]
		human h[5];
		类名 对象数组[元素个数] = { 类名(实参表),...... };
	human h[5] = { human(20, "张三"),human(20,"赵云")，human(20,"关羽") };
	    类名 对象数组[] = { 类名(实参表),...... };
		2.在堆中定义 / 销毁单个对象
			类名 * 对象指针 = new 类名；
			human * ph = new human;
		类名* 对象指针 = new 类名();
			human * ph = new human();
			ph->getinfo();
			delete ph;
			ph->NULL;
	    类名*  对象指针=new 类名(实参表)
			human * ph = new human(10,"张飞");
	在堆中定义 / 销毁单个对象数组
	    类名* 对象数组指针= new 类名[元素个数]
		human * ph = new human[2];
	类名 * 对象数组指针 = new  类名[元素个数]{类名(实参表),}
	human* ph = new human[2]{ human(10,"张飞"),};
delete[]对象数组指针;

***********************************************************
C++标准库--string类
operator=//拷贝赋值函数
c++标准库设计的string类  内部有一个成员 char* m_psz->一个字符串
//代码的设计者
int main(void)
{
	string s1("hello");//定义s1,利用s1.string("hello")-->s1维护的对象为/hello
	cout << "s1:" << sl.c_str() << endl;
	//如果做初始化，并且"="两边的类型完全一致，那么=XXX 和(XXX)无差别
	string s2(s1);//定义s2,利用s2.string(s1)--> s2维护的字符串和s1维护的字符串相同，但地址不同
	string s3;//定义s3，并利用s3.string()-->维护的字符串为"\0"
	s3 = s2//如果在做赋值，并且"="两个类型相同，那么将触发拷贝函数的调用(释放旧资源，分配新资源，拷贝新内容)  s3.operator=(s2)
	string s4 = "hello";//定义s4，只要"="两边的类型不同，编译器会将等号右边的类型转化为等号左边的类型
	//定义匿名对象-->s4维护的字符串和匿名的string类对象维护的字符串 内容相同
	//s4-->维护的字符串为"hello"
	string s5;//定义s5，并利用s5.string()-->维护的字符串为"\0"
	s5="hello"//定义匿名对象-,匿名string类对象.string("hello")-->匿名string类对象维护的字符串为"hello"
		//s5=匿名string类对象;-->s5维护的字符串和匿名string类对象维护的字符串内容相同
		//s5-->维护的字符串内容为"hello"